package com.xbongbong.paas.script.controller;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.xbongbong.paas.constant.PaasConstant;
import com.xbongbong.paas.elasticsearch.util.EsHelper;
import com.xbongbong.paas.enums.DelEnum;
import com.xbongbong.paas.enums.IndexTypeEnum;
import com.xbongbong.paas.help.ProUpdateHelp;
import com.xbongbong.paas.script.pojo.dto.ScriptBaseDTO;
import com.xbongbong.paas.toolbox.exception.XbbException;
import com.xbongbong.paas.toolbox.util.CollectionsUtil;
import com.xbongbong.paas.toolbox.wrap.BaseVO;
import com.xbongbong.paas.toolbox.wrap.XbbResponse;
import com.xbongbong.paas.util.ExplainUtil;
import com.xbongbong.pro.config.ProBaseConfig;
import com.xbongbong.pro.constant.XbbProConstant;
import com.xbongbong.pro.domain.entity.UpdateDataEntity;
import com.xbongbong.pro.enums.ErrorCodeEnum;
import com.xbongbong.pro.enums.errorcodes.SystemErrorCodeEnum;
import com.xbongbong.pro.script.pojo.dto.FixContactLinkCustomerDTO;
import com.xbongbong.pro.script.pojo.dto.SyncContactUserDTO;
import com.xbongbong.pro.script.pojo.vo.ScriptVO;
import com.xbongbong.saas.constant.BasicConstant;
import com.xbongbong.saas.constant.StringConstant;
import com.xbongbong.saas.domain.dao.ContactDao;
import com.xbongbong.saas.domain.entity.ext.ContactEntityExt;
import com.xbongbong.saas.domain.entity.ext.CustomerEntityExt;
import com.xbongbong.saas.model.ContactModel;
import com.xbongbong.saas.model.CustomerModel;
import com.xbongbong.saas.service.RepairExplainService;
import com.xbongbong.sys.model.ConnectorConfigModel;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.MediaType;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;
import javax.validation.Valid;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;

import static org.elasticsearch.index.query.QueryBuilders.boolQuery;
import static org.elasticsearch.index.query.QueryBuilders.termQuery;
import static org.elasticsearch.index.query.QueryBuilders.termsQuery;

/**
 * 联系人相关的修复脚本
 * 创建时间 2021/11/9 9:40 AM
 * 修改时间 2021/11/9 9:40 AM
 * @author chy
 */
@RestController
@RequestMapping(XbbProConstant.API_ROOT_PREFIX + "/script/contact")
public class ContactScriptController {
    private static final Logger LOG = LoggerFactory.getLogger(ContactScriptController.class);

    @Resource
    private ProBaseConfig proBaseConfig;
    @Resource
    private ConnectorConfigModel connectorConfigModel;
    @Resource
    private ContactModel contactModel;
    @Resource
    private CustomerModel customerModel;
    @Resource
    private ContactDao contactDao;
    @Resource
    private EsHelper esHelper;
    @Resource
    private ProUpdateHelp proUpdateHelp;
    @Resource
    private RepairExplainService repairExplainService;

    /**
     *  修复如下Sql联系人中的脏数据
     *  SELECT * FROM  tb_saas_contact WHERE  corpid = '1' and JSON_EXTRACT(data, "$.text_13")  =  ''
     * @author lijiangren
     * @date 2022-02-21 15 41
     */
    @RequestMapping(value = "/fixContactLinkCustomerName", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
    public String fixContactLinkCustomer(@RequestBody @Valid FixContactLinkCustomerDTO fixContactLinkCustomerDTO, BindingResult br) throws Exception {
        if (!proBaseConfig.getXbbCode().equals(fixContactLinkCustomerDTO.getXbbCode())) {
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100006, SystemErrorCodeEnum.API_ERROR_100006.getMsg());
        }
        XbbResponse<String> response;
        if (br.hasErrors()) {
            String errMsg = Objects.requireNonNull(br.getFieldError()).getDefaultMessage();
            response = new XbbResponse<>(SystemErrorCodeEnum.API_ERROR_100002, errMsg);
        } else {
            String res = fixContactLinkCustomerName(fixContactLinkCustomerDTO);
            response = new XbbResponse<>(res);
        }
        return JSON.toJSONString(response);
    }

    private String fixContactLinkCustomerName(FixContactLinkCustomerDTO fixContactLinkCustomerDTO) throws XbbException {
        try {
            Long startTime = System.currentTimeMillis();
            String corpid = fixContactLinkCustomerDTO.getCorpid();
            Integer total = 0;
            Long startId = 0L;
            Integer pageSize = 500;
            boolean flag = true;
            while (flag) {
                List<ContactEntityExt> contactList = contactModel.getFixContactLinkCustomerName(corpid, startId, pageSize);
                Integer count = contactList.size();
                total = total + count;
                //再翻页会查不到数据
                if (count < pageSize) {
                    flag = false;
                }
                //查不到数据，不执行逻辑
                if (Objects.equals(count, 0)) {
                    continue;
                }

                //通过联系人获取关联的客户ID集合
                List<Long> customerIdIn =  new ArrayList<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
                for (ContactEntityExt contact : contactList) {
                    JSONObject data = contact.getData();
                    if (Objects.nonNull(data) && Objects.nonNull(data.get("text_2"))) {
                        Long customerId = Long.valueOf(data.get("text_2").toString());
                        customerIdIn.add(customerId);
                    }
                }

                //根据客户ID集合批量查询客户集并组合成Map
                Map<Long, CustomerEntityExt>  keyMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
                if (CollectionsUtil.isNotEmpty(customerIdIn)) {
                    Map<String, Object> customerParam = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
                    customerParam.put("corpid", corpid);
                    customerParam.put("idIn", customerIdIn);
                    customerParam.put("del", 0);
                    List<CustomerEntityExt> customerEntityExts = customerModel.findEntitys(customerParam);
                    if (CollectionsUtil.isNotEmpty(customerEntityExts)) {
                        for (CustomerEntityExt customerEntityExt : customerEntityExts) {
                            keyMap.put(customerEntityExt.getId(),customerEntityExt);
                        }
                    }
                }

                //组合需要批量更新的数据对象
                List<UpdateDataEntity> updateDataEntityList = new ArrayList<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
                for (ContactEntityExt entity : contactList) {
                    JSONObject data = entity.getData();
                    if (Objects.nonNull(data) && Objects.nonNull(data.get("text_2"))) {
                        Long customerId = Long.valueOf(data.get("text_2").toString());
                        CustomerEntityExt customerEntityExt = keyMap.get(customerId);
                        if (Objects.nonNull(customerEntityExt) && Objects.nonNull(customerEntityExt.getData()) && Objects.nonNull(customerEntityExt.getData().get("text_1"))) {
                            JSONObject temp = new JSONObject();
                            temp.put("text_13", customerEntityExt.getData().get("text_1"));
                            UpdateDataEntity updateData = ExplainUtil.getUpdateData(entity.getId(), temp, corpid);
                            //LOG.info("dataid:{},text_1{}",updateData.getId(),customerEntityExt.getData().get("text_1"));
                            updateDataEntityList.add(updateData);
                        }
                    }
                }

                //批量更新
                if (CollectionsUtil.isNotEmpty(updateDataEntityList)) {
                    proUpdateHelp.updateBatch(1, 401, corpid, updateDataEntityList);
                }
                //下一轮循环的startId
                LOG.info("已完成{}条数据更新",total);
                startId = contactList.get(contactList.size()-1).getId();
            }
            Long endTime = System.currentTimeMillis();
            LOG.info("needTime:{}",(endTime - startTime));
            LOG.info("totalUpdateCount:{}",total);
            return "success";
        } catch (XbbException e) {
            e.printStackTrace();
            return "false";
        }
    }

    @RequestMapping(value = "/fixConnectorContact", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
    public String fixConnectorContact(@RequestBody @Valid ScriptBaseDTO scriptBaseDTO, BindingResult br) {
        XbbResponse<BaseVO> response;
        if (br.hasErrors()) {
            String errMsg = Objects.requireNonNull(br.getFieldError()).getDefaultMessage();
            response = new XbbResponse<>(SystemErrorCodeEnum.API_ERROR_100002, errMsg);
        } else {
            try {
                if (!Objects.equals(scriptBaseDTO.getXbbCode(), proBaseConfig.getXbbCode())) {
                    LOG.error("fixConnectorContact 密码错误，停止任务！");
                    throw new XbbException(SystemErrorCodeEnum.API_ERROR_100066);
                }
                String oneCorpid = scriptBaseDTO.getOneCorpid();
                if (Objects.isNull(oneCorpid)) {
                    List<String> corpids = connectorConfigModel.findCorps();
                    Integer count = corpids.size();
                    Integer index = 1;
                    for (String corpid : corpids) {
                        LOG.info(index + "/" + count);
                        LOG.info("corpid:" + corpid);
                        fixConnectorContact(corpid);
                        index ++;
                    }
                } else {
                    fixConnectorContact(oneCorpid);
                    LOG.info("oneCorpid:" + oneCorpid);
                }
                LOG.info("fixConnectorContact finish");
            } catch (Exception e) {
                LOG.error("fixConnectorContact fail", e);
            }

            response = new XbbResponse<>(new BaseVO());
        }
        return JSON.toJSONString(response);
    }

    /**
     * 单公司修复连接器导致的联系人数据错误
     * @param corpid
     * 创建时间 2021/11/9 2:49 PM
     * 修改时间 2021/11/9 2:49 PM
     * @author chy
     */
    private void fixConnectorContact(String corpid) {
        Long startId = 0L;
        Integer pageSize = 100;
        boolean flag = true;
        while (flag) {
            List<ContactEntityExt> contactList = contactModel.getFixConnectorContact(corpid, startId, pageSize);
            Integer count = contactList.size();
            //再翻页会查不到数据
            if (count < pageSize) {
                flag = false;
            }
            //查不到数据，不执行逻辑
            if (Objects.equals(count, 0)) {
                continue;
            }
            List<Long> contactIds = getContactIds(contactList);
            Map<Long, ContactEntityExt> contactMap = getContactMapByEs(corpid, contactIds);
            for (ContactEntityExt contact : contactList) {
                Long id = contact.getId();
                if (!contactMap.containsKey(id)) {
                    continue;
                }
                ContactEntityExt contactEs = contactMap.get(id);
                if (Objects.isNull(contactEs)) {
                    LOG.info("contactEs is null");
                    continue;
                }
                JSONObject esData = contactEs.getData();
                if (Objects.isNull(esData) || esData.isEmpty()) {
                    LOG.info("esData is null or empty");
                    continue;
                }
                contact.setData(esData);
                try {
                    contactDao.update(contact);
                }catch (Exception e) {
                    LOG.error("update error id:" + contact.getId(), e);
                }
            }
            startId = contactList.get(contactList.size()-1).getId();
        }
    }

    /**
     * 获取联系人id集合
     * @param contactList
     * @return
     * 创建时间 2021/11/9 2:00 PM
     * 修改时间 2021/11/9 2:00 PM
     * @author chy
     */
    private List<Long> getContactIds(List<ContactEntityExt> contactList) {
        List<Long> contactIds = new ArrayList<>();
        for (ContactEntityExt contact : contactList) {
            contactIds.add(contact.getId());
        }
        return contactIds;
    }

    /**
     * 通过联系人id从es获取数据
     * @param corpid
     * @param contactIds
     * @return
     * 创建时间 2021/11/9 2:03 PM
     * 修改时间 2021/11/9 2:03 PM
     * @author chy
     */
    private Map<Long, ContactEntityExt> getContactMapByEs(String corpid, List<Long> contactIds) {
        Map<Long, ContactEntityExt> contactMap = new HashMap<>();
        BoolQueryBuilder boolQueryBuilder = boolQuery();
        boolQueryBuilder.filter(termQuery("corpid.keyword", corpid));
        boolQueryBuilder.filter(termsQuery(BasicConstant.DATAID, contactIds));
        boolQueryBuilder.filter(termQuery(StringConstant.DEL, DelEnum.NORMAL.getDel()));
        List<ContactEntityExt> contactEntityExts = null;
        try {
            contactEntityExts = esHelper.findByScroll(IndexTypeEnum.IDX_SAAS_CONTACT,boolQueryBuilder,ContactEntityExt.class,null);
        } catch (XbbException e) {
            return contactMap;
        }
        for (ContactEntityExt contact : contactEntityExts) {
            contactMap.put(contact.getDataId(), contact);
        }
        return contactMap;
    }

    /**
     *
     * @Description: 同步联系人团队数据，保持和客户团队一致
     * @param syncContactUserDTO
     * @param br
     * @return: java.lang.String
     * @Date: 2022/9/19
     */
    @RequestMapping(value = "/syncContactUser", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
    public String syncContactUser(@RequestBody @Valid SyncContactUserDTO syncContactUserDTO, BindingResult br) throws XbbException {
        if ( !Objects.equals(proBaseConfig.getXbbCode(),syncContactUserDTO.getXbbCode()) ){
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100006);
        }
        XbbResponse<ScriptVO> response;
        if (br.hasErrors()) {
            String errMsg = Objects.requireNonNull(br.getFieldError()).getDefaultMessage();
            response = new XbbResponse<>(SystemErrorCodeEnum.API_ERROR_100002, errMsg);
        } else {
            try {
                ScriptVO scriptVO = repairExplainService.syncContactUser(syncContactUserDTO);
                response = new XbbResponse<>(scriptVO);
            } catch (XbbException e) {
                response = new XbbResponse<>(e);
            }
        }
        return JSON.toJSONString(response);
    }

}
